/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.loaders; import java.beans.*; import java.text.MessageFormat; import org.openide.TopManager; import org.openide.cookies.OpenCookie; import org.openide.cookies.ViewCookie; import org.openide.cookies.CloseCookie; import org.openide.filesystems.*; import org.openide.windows.TopComponent; import org.openide.windows.CloneableTopComponent; import org.openide.util.WeakListener; /** Simple support for an openable file. * Can be used either as an {@link OpenCookie}, {@link ViewCookie}, or {@link CloseCookie}, * depending on which cookies the subclass implements. * * @author Jaroslav Tulach */ public abstract class OpenSupport extends Object { /** Entry to work with. */ protected MultiDataObject.Entry entry; /** All opened editors on this file. */ protected CloneableTopComponent.Ref allEditors; /** New support for a given entry. The file is taken from the * entry and is updated if the entry moves or renames itself. * @param entry entry to create instance from */ public OpenSupport (MultiDataObject.Entry entry) { this.entry = entry; Listener l = new Listener (entry); this.allEditors = l; final DataObject obj = entry.getDataObject (); if (obj != null) { // attach property change listener to be informed about loosing validity obj.addPropertyChangeListener (WeakListener.propertyChange ( l, obj )); // attach vetoable change listener to be cancel loosing validity when modified obj.addVetoableChangeListener (WeakListener.vetoableChange ( l, obj )); } } /** Focuses existing component to open, or if none exists creates new. * @see OpenCookie#open */ public void open () { CloneableTopComponent editor = openCloneableTopComponent(); editor.requestFocus(); } /** Focuses existing component to view, or if none exists creates new. * The default implementation simply calls {@link #open}. * @see ViewCookie#view */ public void view () { open (); } /** Focuses existing component to view, or if none exists creates new. * The default implementation simply calls {@link #open}. * @see ViewCookie#view */ public void edit () { open (); } /** Closes all components. * @return <code>true</code> if every component is successfully closed or <code>false</code> if the user cancelled the request * @see CloseCookie#close */ public boolean close () { return close (true); } /** Closes all opened windows. * @param ask true if we should ask user * @return true if sucesfully closed */ boolean close (boolean ask) { synchronized (allEditors) { java.util.Enumeration en = allEditors.getComponents (); if (!en.hasMoreElements ()) { // nothing needs to be saved return true; } // user canceled the action if (ask && !canClose ()) { return false; } while (en.hasMoreElements ()) { TopComponent c = (TopComponent)en.nextElement (); if (!c.close ()) { return false; } } } return true; } /** Should test whether all data is saved, and if not, prompt the user * to save. * The default implementation returns <code>true</code>. * * @return <code>true</code> if everything can be closed */ protected boolean canClose () { return true; } /** Simply open for an editor. */ protected final CloneableTopComponent openCloneableTopComponent() { MessageFormat mf = new MessageFormat(DataObject.getString("CTL_ObjectOpen")); DataObject obj = entry.getDataObject(); synchronized (allEditors) { try { CloneableTopComponent ret = (CloneableTopComponent)allEditors.getAnyComponent (); ret.open(); return ret; } catch (java.util.NoSuchElementException ex) { // no opened editor TopManager.getDefault().setStatusText(mf.format ( new Object[] { obj.getName(), obj.getPrimaryFile().toString() } )); CloneableTopComponent editor = createCloneableTopComponent (); editor.setReference (allEditors); editor.open(); TopManager.getDefault ().setStatusText (DataObject.getString ("CTL_ObjectOpened")); return editor; } } } /** A method to create a new component. Must be overridden in subclasses. * @return the cloneable top component for this support */ protected abstract CloneableTopComponent createCloneableTopComponent (); /** Property change & veto listener. To react to dispose/delete of * the data object. */ private static final class Listener extends CloneableTopComponent.Ref implements PropertyChangeListener, VetoableChangeListener { /** generated Serialized Version UID */ static final long serialVersionUID = -1934890789745432531L; /** entry to serialize */ private MultiDataObject.Entry entry; /** Constructor. */ public Listener (MultiDataObject.Entry entry) { this.entry = entry; } public void propertyChange (PropertyChangeEvent ev) { if (DataObject.PROP_VALID.equals (ev.getPropertyName ())) { // loosing validity DataObject obj = entry.getDataObject (); OpenSupport os = (OpenSupport)obj.getCookie (OpenSupport.class); if (!obj.isValid () && os != null) { // mark the object as not being modified, so nobody // will ask for save obj.setModified (false); os.close (false); } } } /** Forbids setValid (false) on data object when there is an * opened editor. * * @param ev PropertyChangeEvent */ public void vetoableChange (PropertyChangeEvent ev) throws PropertyVetoException { if (DataObject.PROP_VALID.equals (ev.getPropertyName ())) { // loosing validity DataObject obj = entry.getDataObject (); if (obj.isValid () && obj.isModified ()) { OpenSupport os = (OpenSupport)obj.getCookie (OpenSupport.class); if (os != null && !os.close (true)) { // is modified and has not been sucessfully closed throw new PropertyVetoException ( obj.getPrimaryFile ().toString (), ev ); } } } } /** Resolvable to connect to the right data object. This * method is used for connectiong CloneableTopComponents via * their CloneableTopComponent.Ref */ public Object readResolve () { DataObject obj = entry.getDataObject (); OpenSupport os = (OpenSupport)obj.getCookie (OpenSupport.class); if (os == null) { // problem! no replace!? return this; } // use the editor support's CloneableTopComponent.Ref return os.allEditors; } } } /* * Log * 20 src-jtulach1.19 12/8/99 Jaroslav Tulach TopComponent enhanced. * 19 src-jtulach1.18 11/5/99 Jaroslav Tulach WeakListener has now * registration methods. * 18 src-jtulach1.17 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 17 src-jtulach1.16 9/30/99 Jaroslav Tulach * 16 src-jtulach1.15 9/30/99 Jaroslav Tulach OpenSupport is attached * to setValid veto change of its data object. * 15 src-jtulach1.14 9/13/99 Jaroslav Tulach #2628 * 14 src-jtulach1.13 9/13/99 Jan Jancura Do not write "Opening * blablabla" when no new document is opened - only focused. * 13 src-jtulach1.12 7/13/99 Ales Novak new win sys change * 12 src-jtulach1.11 7/11/99 David Simonek window system change... * 11 src-jtulach1.10 6/22/99 Ales Novak creating of editors is * centralized * 10 src-jtulach1.9 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 9 src-jtulach1.8 4/2/99 Jaroslav Tulach New from template opens * the editor. * 8 src-jtulach1.7 3/31/99 David Simonek ugly ugly ugly * requestFocus bungs fixed * 7 src-jtulach1.6 3/17/99 Jaroslav Tulach Output Window fixing. * 6 src-jtulach1.5 3/15/99 Jesse Glick [JavaDoc] * 5 src-jtulach1.4 3/14/99 Jaroslav Tulach Change of * MultiDataObject.Entry. * 4 src-jtulach1.3 3/10/99 Jesse Glick [JavaDoc] * 3 src-jtulach1.2 2/3/99 Jaroslav Tulach * 2 src-jtulach1.1 1/17/99 Jaroslav Tulach open/close/canClose * methods * 1 src-jtulach1.0 1/7/99 Jaroslav Tulach * $ */